using System;
using System.Collections.Generic;
using System.Text;
using System.Collections;

using RS.DOM.Common;
using RS.DOM.Types;

namespace RS.DOM.Construction
{
    public class Document: LineCollection
    {
        #region Constructors

        public Document(string text)
        {
            m_text = text;
            m_lines = new LineCollection();
            m_docArea = new DocArea();
            m_context = new Context(this, null, null);
            m_log = new List<string>();
            
            this.AddLines();
        }

        #endregion

        #region Members

        private LineCollection m_lines;
        private string m_text;
        private string m_output;
        private string m_error;
        private List<string> m_log;
        public DocArea m_docArea;
        public Context m_context;
        public static Hashtable m_variables = new Hashtable();

        #endregion

        #region Methods

        public static void ClearState()
        {
            m_variables.Clear();
        }

        public Token Execute()
        {
            Token token = null;
            m_output = "";
            m_error = string.Empty;
            m_log.Clear();

            if (this.Count > 0)
            {
                foreach (Line line in this)
                {
                    try
                    {
                        token = line.Execute();
                        m_output += token.ToString() + "\r\n";
                    }
                    catch (Exception ex)
                    {
                        m_error = ex.Message;
                        break;
                    }
                }
            }
            else
            {
                m_output = "Hello World !";
            }

            return token;
        }

        public override void Build()
        {
            m_lines.Build();

            //split by parts
            foreach (Line line in m_lines)
            {
                foreach (Token token in line)
                {
                    if (token.Text == "g" ||
                        token.Text == "group") //group
                    {
                        this.Add(new Group(this.Context));
                        continue;
                    }
                    else if (line.IndexOf(token) == 0) //by default it's expression
                    {
                        this.Add(new Expression(this.Context));
                    }

                    this.LastLine.Add(token);
                }
            }

            base.Build();
        }

        private void AddLines()
        {
            string[] lines = this.Text.Split(new char[] { '\n' }, 
                                             StringSplitOptions.RemoveEmptyEntries);

            //comments
            foreach (string text in lines)
            {
                int startComment = text.IndexOf("//");

                string textLine = string.Empty;
                if (startComment >= 0)
                    textLine = text.Substring(0, startComment);
                else
                    textLine = text;

                if (textLine.Length > 0)
                {
                    TextLine line = new TextLine(this.Context, textLine, true);
                    m_lines.Add(line);
                }
            }
        }

        public void AddLog(string text)
        {
            m_log.Add(text);
        }

        public void AddVariable(string text, Token token)
        {
            if (m_variables.Contains(text))
            {
                ((Token)m_variables[text]).Result = token.Result;
            }
            else
            {
                m_variables.Add(text, token);
            }
        }

        public Token GetVariable(string text)
        {
            string textWithoutNumbers = this.GetTextWithoutNumbers(text);

            if (m_variables.Contains(textWithoutNumbers))
            {
                Token token = (Token)m_variables[textWithoutNumbers];
                token.Text = text;

                if(text!=textWithoutNumbers)
                    token = token.Copy();
                    
                return token;
            }
            else
            {
                return null;
            }
        }

        private string GetTextWithoutNumbers(string text)
        {
            for(int i=0; i<10; i++)
                text = text.Replace(i.ToString(), "");

            return text;
        }

        #endregion

        #region Properties

        public DocArea Area
        {
            get
            {
                return m_docArea;
            }
        }

        public Context Context
        {
            get
            {
                return m_context;
            }
        }

        public string Text
        {
            get 
            { 
                return m_text; 
            }

            set 
            { 
                m_text = value; 
            }
        }

        public List<string> Log
        {
            get
            {
                return m_log;
            }
        }

        public string Output
        {
            get
            {
                return m_output;
            }

            set
            {
                m_output = value;
            }
        }

        public bool HasError
        {
            get
            {
                return (m_error != string.Empty);
            }
        }

        public string Error
        {
            get
            {
                return m_error;
            }
        }

        #endregion
    }
}